//汉明距离指的是两个长度相同的序列在相同位置上有多少个符号不同,对二进制序列来说，也就是相异的位数。
//将一个序列转换成另一个序列所需的替换次数就是汉明距离。
use std::time::Instant;

fn hamming_distance1(source: u64, target: u64) -> u32 {
    let mut distance = 0;
    let mut xor = source ^ target;

    //异或取值
    while xor != 0 {
        distance += xor & 1;
        xor >>= 1;
    }
    distance as u32
}

fn hamming_distance2(source: u64, target: u64) -> u32 {
    let mut xor = source ^ target;
    let mut diff = xor;

    while xor != 0 {
        xor >>= 1;
        diff -= xor;
    }
    diff as u32 
}

fn hamming_distance3(source: u64, target: u64) -> u32 {
    let xor = source ^ target;
    let mut remaining = xor;
    let mut sum = 0;
    while remaining != 0 {
        remaining >>= 1;
        sum += remaining;
    }
    (xor - sum) as u32
}
#[warn(dead_code)]
fn hamming_distance4(source: u64, target: u64) -> u32 {
    (source ^ target).count_ones()
}

fn hamming_distance_str(source: &str, target: &str) -> u32 {
    let mut count = 0;
    let mut source = source.chars();
    let mut target = target.chars();

    /*两个字符串逐字符比较可能出现如下四种情况
     *1.都有下一个字符，不等时距离加1
     *2.都有下一个字符，相等时继续比较下一个字符
     *3.都没有下一个字符，则完成比较
     *4.一边有，一边没有，则长度都不同
     */
    loop {
        match (source.next(), target.next()) {
            (Some(cs), Some(ct)) if cs != ct => count += 1,
            (Some(_), None) | (None, Some(_)) => panic!("Error: mismatched length!"),
            (None, None) => break,
            _ => continue,
        }
    }
    count as u32 
}

fn main() {
    let s_time = Instant::now();
    let source = 1;
    let target = 2;
    let distance = hamming_distance1(source, target);
    println!("The hamming distance is {distance}");

    let distance = hamming_distance2(source, target);
    println!("The hamming2 distance is {distance}");

    let distance = hamming_distance3(source, target);
    println!("The hamming3 distance is {distance}");

    let distance = hamming_distance4(source, target);
    println!("The hamming4 distance is {distance}");

    let source = "abce";
    let target = "edcf";
    let distance = hamming_distance_str(source, target);
    println!("The string hamming distance is {distance}");
    println!("Time cost: {:?}ms", s_time.elapsed().as_millis());

}
